package com.qdxwx.common.utils;

import jakarta.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.URLEncoder;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;

/**
 * Qdx NetSchool Platform
 * @author qdxwx
 * @updateTime 2022/5/25
 * @description
 */
public class TKRequest {
    /**
     * 获取请求Body
     * @param request Servlet
     * @return 请求Body
     */
    public static String getRequestBody(HttpServletRequest request) {
        return getRequestBody(request, StandardCharsets.UTF_8);
    }

    /**
     * 获取请求Body
     * @param request Servlet
     * @param charset 编码
     * @return 请求Body
     */
    public static String getRequestBody(HttpServletRequest request, Charset charset) {
        try {
            InputStream inputStream = request.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, charset));
            StringBuilder sb = new StringBuilder();
            String temp;
            while ((temp = br.readLine()) != null) {
                sb.append(temp);
            }
            br.close();
            inputStream.close();
            return sb.toString();
        } catch (Exception ex) {
            System.out.println(ex.getMessage());
            return null;
        }
    }

    public static String getServerUri(HttpServletRequest request) {
        StringBuilder comeUrl = new StringBuilder();
        String serverName = request.getServerName();
        if (serverName.contains("localhost") || serverName.contains("127.0.0.1")) {
            comeUrl.append("http://");
        } else {
            comeUrl.append("https://");
        }
        comeUrl.append(serverName);
        int port = request.getServerPort();
        if (port != 80 && port != 443) {
            comeUrl.append(":").append(request.getServerPort());
        }
        return comeUrl.toString();
    }

    public static String getComeUrl(HttpServletRequest request) {
        String comeUrl = request.getParameter("come_url");
        if (comeUrl == null) {
            comeUrl = request.getParameter("comeUrl");
            if (comeUrl == null) {
                comeUrl = request.getHeader("referer");
                if (comeUrl == null) {
                    comeUrl = "/";
                }
            }
        }
        comeUrl = TKConvert.toURLDecode(comeUrl);
        if (comeUrl.contains("auth") ||
                comeUrl.contains("login") ||
                comeUrl.contains("logout") ||
                comeUrl.contains("register")) {
            comeUrl = "/";//String.format("%s://%s%s", request.getScheme(), request.getHeader("Host"), request.getContextPath());
        }
        return comeUrl;
    }

    public static boolean isOutPost(HttpServletRequest request) {
        String referer = request.getHeader("referer");
        if (referer == null || referer.length() < 1)
            return true;
        //判断请求页面和getRequestURI是否相同
        String serverName = request.getServerName();
        if (serverName == null || serverName.length() < 1)
            return true;

        int index = 0;
        if (referer.indexOf("https://") == 0)
            index = 8;
        else if (referer.indexOf("http://") == 0)
            index = 7;
        return (referer.length() - index < serverName.length()) ||
                !serverName.equalsIgnoreCase(referer.substring(index, index + serverName.length()));
    }

    public static String getIpAddr(HttpServletRequest request) {
        if (request == null) {
            return "unknown";
        }
        String ip = request.getHeader("X-Forwarded-For");
        if (ip != null && ip.length() > 0 && !"unknown".equalsIgnoreCase(ip)) {
            return ip;
        }
        ip = request.getHeader("Proxy-Client-IP");
        if (ip != null && ip.length() > 0 && !"unknown".equalsIgnoreCase(ip)) {
            return ip;
        }
        ip = request.getHeader("WL-Proxy-Client-IP");
        if (ip != null && ip.length() > 0 && !"unknown".equalsIgnoreCase(ip)) {
            return ip;
        }
        ip = request.getHeader("X-Real-IP");
        if (ip != null && ip.length() > 0 && !"unknown".equalsIgnoreCase(ip)) {
            return ip;
        }
        ip = request.getRemoteAddr();
        return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
    }

    public static boolean internalIp(String ip) {
        byte[] addr = textToNumericFormatV4(ip);
        return internalIp(addr) || "127.0.0.1".equals(ip);
    }

    private static boolean internalIp(byte[] addr) {
        if (addr == null || addr.length < 2) {
            return true;
        }
        final byte b0 = addr[0];
        final byte b1 = addr[1];
        // 10.x.x.x/8
        final byte SECTION_1 = 0x0A;
        // 172.16.x.x/12
        final byte SECTION_2 = (byte) 0xAC;
        final byte SECTION_3 = (byte) 0x10;
        final byte SECTION_4 = (byte) 0x1F;
        // 192.168.x.x/16
        final byte SECTION_5 = (byte) 0xC0;
        final byte SECTION_6 = (byte) 0xA8;
        switch (b0) {
            case SECTION_1:
                return true;
            case SECTION_2:
                if (b1 >= SECTION_3 && b1 <= SECTION_4) {
                    return true;
                }
            case SECTION_5:
                if (b1 == SECTION_6) {
                    return true;
                }
            default:
                return false;
        }
    }

    /**
     * 将IPv4地址转换成字节
     *
     * @param text IPv4地址
     * @return byte 字节
     */
    public static byte[] textToNumericFormatV4(String text) {
        if (text.length() == 0) {
            return null;
        }

        byte[] bytes = new byte[4];
        String[] elements = text.split("\\.", -1);
        try {
            long l;
            int i;
            switch (elements.length) {
                case 1:
                    l = Long.parseLong(elements[0]);
                    if ((l < 0L) || (l > 4294967295L))
                        return null;
                    bytes[0] = (byte) (int) (l >> 24 & 0xFF);
                    bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF);
                    bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
                    bytes[3] = (byte) (int) (l & 0xFF);
                    break;
                case 2:
                    l = Integer.parseInt(elements[0]);
                    if ((l < 0L) || (l > 255L))
                        return null;
                    bytes[0] = (byte) (int) (l & 0xFF);
                    l = Integer.parseInt(elements[1]);
                    if ((l < 0L) || (l > 16777215L))
                        return null;
                    bytes[1] = (byte) (int) (l >> 16 & 0xFF);
                    bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
                    bytes[3] = (byte) (int) (l & 0xFF);
                    break;
                case 3:
                    for (i = 0; i < 2; ++i) {
                        l = Integer.parseInt(elements[i]);
                        if ((l < 0L) || (l > 255L))
                            return null;
                        bytes[i] = (byte) (int) (l & 0xFF);
                    }
                    l = Integer.parseInt(elements[2]);
                    if ((l < 0L) || (l > 65535L))
                        return null;
                    bytes[2] = (byte) (int) (l >> 8 & 0xFF);
                    bytes[3] = (byte) (int) (l & 0xFF);
                    break;
                case 4:
                    for (i = 0; i < 4; ++i) {
                        l = Integer.parseInt(elements[i]);
                        if ((l < 0L) || (l > 255L))
                            return null;
                        bytes[i] = (byte) (int) (l & 0xFF);
                    }
                    break;
                default:
                    return null;
            }
        } catch (NumberFormatException e) {
            return null;
        }
        return bytes;
    }

    public static String getHostIp() {
        try {
            return InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException ignored) {
        }
        return "127.0.0.1";
    }

    public static String getHostName() {
        try {
            return InetAddress.getLocalHost().getHostName();
        } catch (UnknownHostException ignored) {
        }
        return "未知";
    }

    public static String getUserAgent(HttpServletRequest request) {
        return request.getHeader("User-Agent");
    }

    //判断是否为手机浏览器
    public static boolean isMobileBrowse(HttpServletRequest request) {
        boolean isMobile = false;
        String[] mobileAgents = {"micromessenger", "android", "phone", "ipad", "mobi", "huawei", "wap", "netfront", "java",
                "opera", "ucweb", "windows ce", "symb", "seri", "webos", "sony", "blac", "dopod",
                "noki", "samsung", "palmsource", "xda", "pieplus", "meizu", "midp", "cldc", "moto", "foma",
                "doco", "up.browser", "up.link", "blaz", "helio", "hosin", "novarra", "coolpad",
                "techfaith", "alca", "amoi", "ktouch", "nexian", "eric", "phil", "sage",
                "wellcom", "bunjalloo", "maui", "spice", "bird", "zte-", "longcos",
                "pant", "gionee", "port", "jig browser", "hipt", "benq", "haier", "^lct", "320x320",
                "240x320", "176x220", "w3c ", "acs-", "alav", "audi", "avan",
                "brew", "cell", "cmd-", "dang", "inno", "ipaq", "jigs",
                "kddi", "keji", "leno", "lg-c", "lg-d", "lg-g", "lge-", "maxo", "mits", "mmef",
                "mot-", "mwbp", "nec-", "newt", "palm", "pana", "play",
                "prox", "sany", "sch-", "sec-", "send", "sgh-", "shar", "sie-", "siem",
                "smal", "smar", "sph-", "t-mo", "teli", "tim-", "tosh", "tsm-", "upg1", "upsi", "vk-v",
                "voda", "webc", "winw"};

        String agent = request.getHeader("User-Agent");
        if (agent != null) {
            agent = agent.toLowerCase();
            for (String mobileAgent : mobileAgents) {
                if (agent.contains(mobileAgent) && !agent.contains("windows nt") && !agent.contains("macintosh")) {
                    isMobile = true;
                    break;
                }
            }
        }
        return isMobile;
    }
    //判断是否为微信浏览器
    public static boolean isWxBrowse(HttpServletRequest request) {
        String agent = request.getHeader("User-Agent");
        if (agent == null) {
            return false;
        }
        return agent.toLowerCase().contains("micromessenger");
    }

    //检查请求是否为ajax
    public static boolean isAjaxRequest(HttpServletRequest request) {
        String accept = request.getHeader("Accept");
        if (accept != null && accept.contains("json")) {
            return true;
        }
        String contentType = request.getHeader("Content-Type");
        if (contentType != null && contentType.contains("json")) {
            return true;
        }
        String xRequestedWith = request.getHeader("X-Requested-With");
        if ("XMLHttpRequest".equalsIgnoreCase(xRequestedWith)) {
            return true;
        }
        String uri = request.getRequestURI();
        return (uri.contains(".json") || uri.contains(".xml"));
    }

    public static String getClientOs(HttpServletRequest request){
        return TKClientOs.getName(request);
    }

    /**
     * 获取请求URI
     */
    public static String getRequestUriWithParams(HttpServletRequest request) {
        StringBuilder sbUrlParams = new StringBuilder(request.getRequestURI());
        sbUrlParams.append("?");
        Enumeration<String> parNames = request.getParameterNames();
        while (parNames.hasMoreElements()) {
            String parName = parNames.nextElement();
            sbUrlParams.append(parName).append("=")
                    .append(URLEncoder.encode(request.getParameter(parName), StandardCharsets.UTF_8))
                    .append("&");
        }
        return sbUrlParams.toString();
    }
}
